#include "stdafx.h"

#include "video/fbo.h"

namespace natrium {
	namespace video {
		FrameBufferObject::FrameBufferObject(unsigned int width, unsigned int height) {
			glGenFramebuffers(1, &mHandle);
			glBindFramebuffer(GL_FRAMEBUFFER, mHandle);

			//create/bind depth buffer (renderbuffer type) -- depth component
			glGenRenderbuffers(1, &mDepthBuffer);
			glBindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);

			//create/bind position buffer (texture unit 0) -- rgb as floats
			glActiveTexture(GL_TEXTURE0);
			glGenTextures(1, &mPositionBuffer);
			glBindTexture(GL_TEXTURE_2D, mPositionBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//create/bind normal buffer (texture unit 1) -- rgb as floats
			glActiveTexture(GL_TEXTURE1);
			glGenTextures(1, &mNormalBuffer);
			glBindTexture(GL_TEXTURE_2D, mNormalBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//create/bind color buffer (texture unit 2) -- plain rgb (no float)
			glActiveTexture(GL_TEXTURE2);
			glGenTextures(1, &mColorBuffer);
			glBindTexture(GL_TEXTURE_2D, mColorBuffer);
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			//attach images to the framebuffer
			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBuffer);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mPositionBuffer, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mNormalBuffer, 0);
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mColorBuffer, 0);

			GLenum drawBuffers[] = {
				GL_NONE,
				GL_COLOR_ATTACHMENT0,
				GL_COLOR_ATTACHMENT1,
				GL_COLOR_ATTACHMENT2
			};

			glDrawBuffers(4, drawBuffers);

			glBindFramebuffer(GL_FRAMEBUFFER, 0);
		}

		FrameBufferObject::~FrameBufferObject() {
			glDeleteFramebuffers(1, &mHandle);

			glDeleteTextures(1, &mPositionBuffer);
			glDeleteTextures(1, &mNormalBuffer);
			glDeleteTextures(1, &mColorBuffer);

			glDeleteRenderbuffers(1, &mDepthBuffer);
		}

		GLuint FrameBufferObject::getDepthBuffer() const {
			return mDepthBuffer;
		}

		GLuint FrameBufferObject::getPositionBuffer() const {
			return mPositionBuffer;
		}

		GLuint FrameBufferObject::getNormalBuffer() const {
			return mNormalBuffer;
		}

		GLuint FrameBufferObject::getColorBuffer() const {
			return mColorBuffer;
		}

		GLuint FrameBufferObject::getHandle() const {
			return mHandle;
		}
	}
}